pub(crate) struct IoVec<'a>(&'a [&'a[u8]], usize);

impl<'a> IoVec<'a> {
    pub fn new(buf: &'a [&'a [u8]], off: usize) -> Self {
        Self(buf, 0).next_bytes(off)
    }
    pub fn next_bytes(&self, bytes_off: usize) -> Self {
        let mut off = bytes_off + self.1;
        for (index, item) in self.0.iter().enumerate() {
            if off < item.len() {
                return Self(&self.0[index..], off);
            }
            off -= item.len();
        }
        Self(&self.0[0..0], 0)
    }
    pub fn next_iovec(&self, iovec_off: usize) -> Self {
        if iovec_off < self.0.len() {
            Self(&self.0[iovec_off..], 0)
        } else {
            Self(&self.0[0..0], 0)
        }
    }

    pub fn to_iovec(&self, iov: &mut [libc::iovec]) -> Option<(*const libc::iovec, i32, usize)> {
        let mut size = 0_usize;
        let mut cnt = 0_i32;
        let mut off = self.1;
        for (index, (iovec, buf)) in iov.iter_mut().zip(self.0.iter()).enumerate() {
            if off == 0 {
                iovec.iov_base = buf.as_ptr().cast_mut().cast::<libc::c_void>();
                iovec.iov_len = buf.len();
            } else {
                iovec.iov_base = buf[off..].as_ptr().cast_mut().cast::<libc::c_void>();
                iovec.iov_len = buf.len() - off;
                off = 0;
            }
            size += iovec.iov_len;
            cnt = index as i32;
        }
        if size > 0 {
            Some((&iov[0], cnt + 1, size))
        } else {
            None
        }
    }
}

pub(crate) struct IoVecMut<'a>(&'a [&'a mut [u8]], usize);

impl<'a> IoVecMut<'a> {
    pub fn new(buf: &'a [&'a mut [u8]], off: usize) -> Self {
        Self(buf, 0).next_bytes(off)
    }
    pub fn next_bytes(&self, bytes_off: usize) -> Self {
        let mut off = bytes_off + self.1;
        for (index, item) in self.0.iter().enumerate() {
            if off < item.len() {
                return Self(&self.0[index..], off);
            }
            off -= item.len();
        }
        Self(&self.0[0..0], 0)
    }
    pub fn next_iovec(&self, iovec_off: usize) -> Self {
        if iovec_off < self.0.len() {
            Self(&self.0[iovec_off..], 0)
        } else {
            Self(&self.0[0..0], 0)
        }
    }

    pub fn to_iovec(&self, iov: &mut [libc::iovec]) -> Option<(*const libc::iovec, i32, usize)> {
        let mut size = 0_usize;
        let mut cnt = 0_i32;
        let mut off = self.1;
        for (index, (iovec, buf)) in iov.iter_mut().zip(self.0.iter()).enumerate() {
            if off == 0 {
                iovec.iov_base = buf.as_ptr().cast_mut().cast::<libc::c_void>();
                iovec.iov_len = buf.len();
            } else {
                iovec.iov_base = buf[off..].as_ptr().cast_mut().cast::<libc::c_void>();
                iovec.iov_len = buf.len() - off;
                off = 0;
            }
            size += iovec.iov_len;
            cnt = index as i32;
        }
        if size > 0 {
            Some((&iov[0], cnt + 1, size))
        } else {
            None
        }
    }
}
